package jym.tan.tmdb;

import jym.tan.tmdb.bean.AlternativeTitleWrapper;
import jym.tan.tmdb.bean.MovieInfo;
import jym.tan.tmdb.bean.MovieSearchWrapper;
import jym.tan.tmdb.constant.TMDBConstants;
import jym.tan.tmdb.method.MovieAlternativeTitles;
import jym.tan.tmdb.method.SearchMovies;

/**
 * The class <code>TMDB</code> is used to manipulate the TMDb API 3.
 * <p>
 * 	For more information see <a href="http://help.themoviedb.org/kb/api/about-3">About 3</a>.
 * </p>
 * It is a singleton class. To get an instance of this class you should invoke 
 * the {@link #getInstance(String)} method with a valid TheMovieDb API key.
 * 
 * @author Tanmoy
 *
 */
public class TMDB {

	private static final Object OBJECT_LOCK = new Object();
	
	private static TMDB tmdb;	
	
	private String key;
	
	private SearchMovies searchMovies = new SearchMovies(this);
	private jym.tan.tmdb.method.MovieInfo movieInfo = new jym.tan.tmdb.method.MovieInfo(this);
	private MovieAlternativeTitles movieAlternativeTitles = new MovieAlternativeTitles(this);
	/**
	 * Don't let anyone else instantiate this class.
	 */
	private TMDB(String key) {
		this.key = key;
	}
	
	/**
	 * Returns the TheMovieDb API Key.
	 * @return
	 * 		The key
	 */
	public String getKey() {
		return key;
	}
	
	/**
	 * Get an instance of <code>TMDB</code> class.
	 * @param key
	 * 		The TheMovieDb API key
	 * 
	 * @return 
	 * 		The <code>TMDB</code> object
	 */
	public static final TMDB getInstance(String key) {
		if(tmdb == null) {
			synchronized (OBJECT_LOCK) {
				tmdb = new TMDB(key);
			}
		}
		return tmdb;
	}
	
	/**
	 * Returns a {@link MovieSearchWrapper} object containing the 
	 * search information associated with the movie name given to it.
	 * <p>
	 * 	For more information see <a href="http://help.themoviedb.org/kb/api/search-movies">Search Movies</a>.
	 * </p>
	 * @param movieName 
	 * 		The name of the movie to be searched 
	 * @return
	 * 		The <code>MovieSearchWrapper</code> object
	 */
	public MovieSearchWrapper searchMovies(String movieName) {
		return searchMovies(movieName, TMDBConstants.BLANK);
	}
	
	/**
	 * Returns a {@link MovieSearchWrapper} object containing the 
	 * search information associated with the movie name given to it.
	 * <p>
	 * 	For more information see <a href="http://help.themoviedb.org/kb/api/search-movies">Search Movies</a>.
	 * </p>
	 * @param movieName 
	 * 		The name of the movie to be searched 
	 * @param year 
	 * 		The movie released year to narrow the search results
	 * @return
	 * 		The <code>MovieSearchWrapper</code> object
	 */
	public MovieSearchWrapper searchMovies(String movieName, String year) {
		return searchMovies(movieName, year, 1);
	}
	
	/**
	 * Returns a {@link MovieSearchWrapper} object containing the 
	 * search information associated with the movie name given to it.
	 * <p>
	 * 	For more information see <a href="http://help.themoviedb.org/kb/api/search-movies">Search Movies</a>.
	 * </p>
	 * @param movieName 
	 * 		The name of the movie to be searched 
	 * @param page 
	 * 		Some searches will have more than 20 results, the default 
	 * 		number of items returned per page. To iterate through use the page parameter.
	 * @return
	 * 		The <code>MovieSearchWrapper</code> object
	 */
	public MovieSearchWrapper searchMovies(String movieName, int page) {
		return searchMovies(movieName, TMDBConstants.BLANK, page);
	}
	
	/**
	 * Returns a {@link MovieSearchWrapper} object containing the 
	 * search information associated with the movie name given to it.
	 * <p>
	 * 	For more information see <a href="http://help.themoviedb.org/kb/api/search-movies">Search Movies</a>.
	 * </p>
	 * @param movieName 
	 * 		The name of the movie to be searched 
	 * @param inculdeAdult 
	 * 		You can toggle whether or not to include adult items in 
	 * 		your search by using this parameter. The expected value is either true or false. 
	 * 		When it is not specified, it is set to false.
	 * @return
	 * 		The <code>MovieSearchWrapper</code> object
	 */
	public MovieSearchWrapper searchMovies(String movieName, boolean inculdeAdult) {
		return searchMovies(movieName, TMDBConstants.BLANK, TMDBConstants.ONE, false, TMDBConstants.BLANK, inculdeAdult);
	}
	
	/**
	 * Returns a {@link MovieSearchWrapper} object containing the 
	 * search information associated with the movie name given to it.
	 * <p>
	 * 	For more information see <a href="http://help.themoviedb.org/kb/api/search-movies">Search Movies</a>.
	 * </p>
	 * @param movieName 
	 * 		The name of the movie to be searched 
	 * @param year 
	 * 		The movie released year to narrow the search results
	 * @param page  
	 * 		Some searches will have more than 20 results, the default 
	 * 		number of items returned per page. To iterate through use the page parameter.
	 * @return
	 * 		The <code>MovieSearchWrapper</code> object
	 */
	public MovieSearchWrapper searchMovies(String movieName, String year, int page) {
		return searchMovies(movieName, year, page, TMDBConstants.BLANK);
	}	
		
	/**
	 * Returns a {@link MovieSearchWrapper} object containing the 
	 * search information associated with the movie name given to it.
	 * <p>
	 * 	For more information see <a href="http://help.themoviedb.org/kb/api/search-movies">Search Movies</a>.
	 * </p>
	 * @param movieName 
	 * 		The name of the movie to be searched 
	 * @param allResults 
	 * 		Some searches will have more than 20 results. So the value 
	 * 		of <code>allResults</code> toggle whether or not the <code>MovieSearchWrapper</code> 
	 * 		object contains all search results 
	 * @param inculdeAdult 
	 * 		You can toggle whether or not to include adult items in 
	 * 		your search by using this parameter. The expected value is either true or false.
	 * @return
	 * 		The <code>MovieSearchWrapper</code> object
	 */
	public MovieSearchWrapper searchMovies(String movieName, boolean allResults, boolean inculdeAdult) {
		return searchMovies(movieName, TMDBConstants.BLANK, TMDBConstants.ONE, allResults, TMDBConstants.BLANK, inculdeAdult);
	}
	
	/**
	 * Returns a {@link MovieSearchWrapper} object containing the 
	 * search information associated with the movie name given to it.
	 * <p>
	 * 	For more information see <a href="http://help.themoviedb.org/kb/api/search-movies">Search Movies</a>.
	 * </p>
	 * @param movieName 
	 * 		The name of the movie to be searched 
	 * @param year 
	 * 		The movie released year to narrow the search results
	 * @param allResults 
	 * 		Some searches will have more than 20 results. So the value 
	 * 		of <code>allResults</code> toggle whether or not the <code>MovieSearchWrapper</code> 
	 * 		object contains all search results 
	 * @return
	 * 		The <code>MovieSearchWrapper</code> object
	 */
	public MovieSearchWrapper searchMovies(String movieName, String year, boolean allResults) {
		return searchMovies(movieName, year, TMDBConstants.ONE, allResults, TMDBConstants.BLANK, Boolean.FALSE);
	}
	
	/**
	 * Returns a {@link MovieSearchWrapper} object containing the 
	 * search information associated with the movie name given to it.
	 * <p>
	 * 	For more information see <a href="http://help.themoviedb.org/kb/api/search-movies">Search Movies</a>.
	 * </p>
	 * @param movieName 
	 * 		The name of the movie to be searched 
	 * @param year 
	 * 		The movie released year to narrow the search results
	 * @param page 
	 * 		Some searches will have more than 20 results, the default 
	 * 		number of items returned per page. To iterate through use the page parameter.
	 * @param language 
	 * 		The language parameter tries to localize the movie data we return. If the 
	 * 		language being requested does not exist, the value will be left blank. 
	 * 		The expected value is a ISO 639-1 code.
	 * @return
	 * 		The <code>MovieSearchWrapper</code> object
	 */
	public MovieSearchWrapper searchMovies(String movieName, String year, int page, String language) {
		return searchMovies(movieName, year, page, Boolean.FALSE, language, Boolean.FALSE);
	}	
	
	/**
	 * Returns a {@link MovieSearchWrapper} object containing the 
	 * search information associated with the movie name given to it.
	 * <p>
	 * 	For more information see <a href="http://help.themoviedb.org/kb/api/search-movies">Search Movies</a>.
	 * </p>
	 * @param movieName 
	 * 		The name of the movie to be searched 
	 * @param year 
	 * 		The movie released year to narrow the search results
	 * @param allResults 
	 * 		Some searches will have more than 20 results. So the value 
	 * 		of <code>allResults</code> toggle whether or not the <code>MovieSearchWrapper</code> 
	 * 		object contains all search results 
	 * @param inculdeAdult 
	 * 		You can toggle whether or not to include adult items in 
	 * 		your search by using this parameter. The expected value is either true or false.
	 * @return
	 * 		The <code>MovieSearchWrapper</code> object
	 */
	public MovieSearchWrapper searchMovies(String movieName, String year, boolean allResults, boolean inculdeAdult) {
		return searchMovies(movieName, year, TMDBConstants.ONE, allResults, TMDBConstants.BLANK, inculdeAdult);
	}
	
	/**
	 * Returns a {@link MovieSearchWrapper} object containing the 
	 * search information associated with the movie name given to it.
	 * <p>
	 * 	For more information see <a href="http://help.themoviedb.org/kb/api/search-movies">Search Movies</a>.
	 * </p>
	 * @param movieName 
	 * 		The name of the movie to be searched 
	 * @param year 
	 * 		The movie released year to narrow the search results
	 * @param allResults 
	 * 		Some searches will have more than 20 results. So the value 
	 * 		of <code>allResults</code> toggle whether or not the <code>MovieSearchWrapper</code> 
	 * 		object contains all search results 
	 * @param language 
	 * 		The language parameter tries to localize the movie data we return. If the 
	 * 		language being requested does not exist, the value will be left blank. 
	 * 		The expected value is a ISO 639-1 code.
	 * @return
	 * 		The <code>MovieSearchWrapper</code> object
	 */
	public MovieSearchWrapper searchMovies(String movieName, String year, boolean allResults, String language) {
		return searchMovies(movieName, year, TMDBConstants.ONE, allResults, language, Boolean.FALSE);
	}
	
	/**
	 * Returns a {@link MovieSearchWrapper} object containing the 
	 * search information associated with the movie name given to it.
	 * <p>
	 * 	For more information see <a href="http://help.themoviedb.org/kb/api/search-movies">Search Movies</a>.
	 * </p>
	 * @param movieName 
	 * 		The name of the movie to be searched 
	 * @param year 
	 * 		The movie released year to narrow the search results
	 * @param allResults 
	 * 		Some searches will have more than 20 results. So the value 
	 * 		of <code>allResults</code> toggle whether or not the <code>MovieSearchWrapper</code> 
	 * 		object contains all search results 
	 * @param language 
	 * 		The language parameter tries to localize the movie data we return. If the 
	 * 		language being requested does not exist, the value will be left blank. 
	 * 		The expected value is a ISO 639-1 code.
	 * @param inculdeAdult 
	 * 		You can toggle whether or not to include adult items in 
	 * 		your search by using this parameter. The expected value is either true or false.
	 * @return
	 * 		The <code>MovieSearchWrapper</code> object
	 */
	public MovieSearchWrapper searchMovies(String movieName, String year, boolean allResults, String language, boolean inculdeAdult) {
		return searchMovies(movieName, year, TMDBConstants.ONE, allResults, language, inculdeAdult);
	}
	
	/**
	 * Returns a {@link MovieSearchWrapper} object containing the 
	 * search information associated with the movie name given to it.
	 * <p>
	 * 	For more information see <a href="http://help.themoviedb.org/kb/api/search-movies">Search Movies</a>.
	 * </p>
	 * @param movieName 
	 * 		The name of the movie to be searched 
	 * @param year 
	 * 		The movie released year to narrow the search results
	 * @param page 
	 * 		Some searches will have more than 20 results, the default 
	 * 		number of items returned per page. To iterate through use the page parameter.
	 * @param allResults 
	 * 		Some searches will have more than 20 results. So the value 
	 * 		of <code>allResults</code> toggle whether or not the <code>MovieSearchWrapper</code> 
	 * 		object contains all search results 
	 * @param language 
	 * 		The language parameter tries to localize the movie data we return. If the 
	 * 		language being requested does not exist, the value will be left blank. 
	 * 		The expected value is a ISO 639-1 code.
	 * @param inculdeAdult 
	 * 		You can toggle whether or not to include adult items in 
	 * 		your search by using this parameter. The expected value is either true or false.
	 * @return
	 * 		The <code>MovieSearchWrapper</code> object
	 */
	public MovieSearchWrapper searchMovies(String movieName, String year, int page, boolean allResults, String language, boolean inculdeAdult) {		
		try {
			return searchMovies.search(movieName, year, page, allResults, language, inculdeAdult);
		} catch (Exception e) {
			return null;
		}
	}
	
	/**
	 * Returns a {@link MovieInfo} object containing the movie information searched for.
	 * <p>
	 * 	For more information see <a href="http://help.themoviedb.org/kb/api/movie-info">Movie Info</a>.
	 * </p>
	 * @param movieId 
	 * 		The TMDB id
	 * @return 
	 * 		The <code>MovieInfo</code> object
	 */
	public MovieInfo getMovieInfo(int movieId) {
		return getMovieInfo(movieId, TMDBConstants.BLANK);
	}
	
	/**
	 * Returns a {@link MovieInfo} object containing the movie information searched for.
	 * <p>
	 * 	For more information see <a href="http://help.themoviedb.org/kb/api/movie-info">Movie Info</a>.
	 * </p>
	 * @param imdbId 
	 * 		The IMDB id
	 * @return 
	 * 		The <code>MovieInfo</code> object 
	 */
	public MovieInfo getMovieInfo(String imdbId) {
		return getMovieInfo(String.valueOf(imdbId), TMDBConstants.BLANK);
	}
	
	/**
	 * Returns a {@link MovieInfo} object containing the movie information searched for.
	 * <p>
	 * 	For more information see <a href="http://help.themoviedb.org/kb/api/movie-info">Movie Info</a>.
	 * </p>
	 * @param movieId 
	 * 		The TMDB id
	 * @param language 
	 * 		The language parameter tries to localize the movie data we return. If the 
	 * 		language being requested does not exist, the value will be left blank. 
	 * 		The expected value is a ISO 639-1 code.
	 * @return 
	 * 		The <code>MovieInfo</code> object 
	 */
	public MovieInfo getMovieInfo(int movieId, String language) {	
		return getMovieInfo(String.valueOf(movieId), language);	
	}
	
	/**
	 * Returns a {@link MovieInfo} object containing the movie information searched for.
	 * <p>
	 * 	For more information see <a href="http://help.themoviedb.org/kb/api/movie-info">Movie Info</a>.
	 * </p>
	 * @param movieId 
	 * 		The TMDB id/ the IMDB id
	 * @param language 
	 * 		The language parameter tries to localize the movie data we return. If the 
	 * 		language being requested does not exist, the value will be left blank. 
	 * 		The expected value is a ISO 639-1 code.
	 * @return 
	 * 		The <code>MovieInfo</code> object 
	 */
	public MovieInfo getMovieInfo(String movieId, String language) {
		try {
			return movieInfo.getMovieInfo(movieId, language);
		} catch (Exception e) {
			return null;
		}		
	}
	
	public AlternativeTitleWrapper getMovieAlternativeTitles(int movieId) {
		return getMovieAlternativeTitles(movieId, TMDBConstants.BLANK);
	}
	
	public AlternativeTitleWrapper getMovieAlternativeTitles(String imdbId) {
		return getMovieAlternativeTitles(imdbId, TMDBConstants.BLANK);
	}
	
	public AlternativeTitleWrapper getMovieAlternativeTitles(int movieId, String country) {
		return getMovieAlternativeTitles(String.valueOf(movieId), country);
	}
	
	public AlternativeTitleWrapper getMovieAlternativeTitles(String movieId, String country) {
		try {
			return movieAlternativeTitles.getAlternativeTitleWrapper(movieId, country);
		} catch (Exception e) {
			return null;
		}
	}
	
	public static void main(String[] args) {
		TMDB tmdb = TMDB.getInstance("23e89da030a0ee8b25aaed20950a0c25");
		
		/** Movie Search Test**/
		MovieSearchWrapper movieSearchWrapper = tmdb.searchMovies("Star Wars");
		System.out.println(movieSearchWrapper);
		
		/** Movie Info Test
		MovieInfo movieInfo = tmdb.getMovieInfo("tt0076759");
		System.out.println(movieInfo);
		**/
		/** Movie Alternative Title Test
		AlternativeTitleWrapper wrapper = tmdb.getMovieAlternativeTitles("tt0076759", "US");
		System.out.println(wrapper);
		**/
	}
}
